[SIM-MDL-008] Внедрить бизнес-инвариант State Lock (BUSY) для Вейбулловских задержек

Синхронизация непрерывного стохастического времени задержек с дискретным шагом симулятора

Author

Simulation Framework Systems Analysis

Published

September 28, 2026

NoteКраткая карточка задачи
  • Репозиторий / Компонент: food-stochastic-simulator / package stochastic.
  • Тип задачи: Алгоритмическая / Бизнес-логика (Core Math).
  • Связанные документы: model.qmd (Раздел 3. Распределение Вейбулла).
  • Статус: Готово к реализации

  • Описание задачи:

    Движок Вейбулла (WeibullEngine) генерирует непрерывную случайную величину длительности действия (delay) твина, округляемую до минут. Возникает алгоритмический рассинхрон: если вычисленное время действия (например, закупка еды в магазине) составляет 3 часа 20 минут, а шаг симулятора равен строго 1 часу, цифровой двойник «улетает» в будущее относительно текущей итерации симулятора. В текущей схеме на следующем часовом тике этот же твин снова начнет выбирать новое действие, что нарушает логику физического времени.

    Необходимо внедрить инвариант блокировки состояний (State Lock) через введение статуса BUSY.

  • Инструкция по шагам:

    1. Расширение структуры состояния шкал: Добавить в системную структуру DynamicState (и типизированную TwinFoodState) новое служебное поле busy_ticks_left (целое число int).
    2. Логика фиксации блокировки: В методе оркестратора processAgentTick после вызова EvaluateBehavior производить расчет: сколько полных часов (тиков симулятора) занимает сгенерированная задержка delay. Если delay > 1 * time.Hour, записывать количество избыточных часов в поле busy_ticks_left.
    3. Перехват и пропуск итераций Маркова: В самом начале метода processAgentTick добавить транзакционный фильтр-барьер. Если busy_ticks_left > 0:
      • Декрементировать счетчик: state["busy_ticks_left"] = busy_ticks_left - 1.
      • Принудительно устанавливать текущее действие в IDLE.
      • Пропускать вызов Марковского движка (PredictNextAction), блокируя принятие новых решений, пока твин физически не завершит предыдущее длительное действие.
    4. Эмиссия логов: Каждое пропущенное из-за блокировки состояние должно уходить в Кафку в топик twin-history-events с флагом текущего действия BUSY_LOCK для сквозного аналитического скоринга.